﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Collections;
using CRMAdminDashboard.CrmSvc;

namespace CRMAdminDashboard
{
    /// <summary>
    /// Represent a "difference" between two RolePrivileges (left and right)
    /// </summary>
    [Serializable]
    public class RoleDiff
    {

        #region Properties

        /// <summary>
        /// Privilege's name in CRM.
        /// </summary>
        public string PrivilegeName { get; set; }

        /// <summary>
        /// Privilege's human readable name, derived from PrivilegeName.
        /// </summary>
        public string PrivilegeNameLong { get; set; }

        /// <summary>
        /// Privilege depth for left RolePrivilege
        /// </summary>
        public PrivilegeDepth? LeftPrivilegeDepth { get; set; }

        /// <summary>
        /// Privilege depth for right RolePrivilege
        /// </summary>
        public PrivilegeDepth? RightPrivilegeDepth { get; set; }

        /// <summary>
        /// Privilege depth for left RolePrivilege (used in TXT output)
        /// </summary>
        public string LeftPrivilegeDepthTxt { get; set; }

        /// <summary>
        /// Privilege depth for right RolePrivilege (used in TXT output)
        /// </summary>
        public string RightPrivilegeDepthTxt { get; set; }

        /// <summary>
        /// Privilege depth for left RolePrivilege (used in CSV output)
        /// </summary>
        public string LeftPrivilegeDepthLong { get; set; }

        /// <summary>
        /// Privilege depth for right RolePrivilege (used in CSV output)
        /// </summary>
        public string RightPrivilegeDepthLong { get; set; }

        #endregion

        #region Entry Points

        /// <summary>
        /// Needed for serializer
        /// </summary>
        public RoleDiff() { }

        /// <summary>
        /// Create a difference instance
        /// </summary>
        /// <param name="allPrivilegesByGuid">Contains all system privileges (SystemPrivilege), keyed by Guid</param>
        public RoleDiff(string privName, Dictionary<Guid, SystemPrivilege> allPrivilegesByGuid, RolePrivilege left, RolePrivilege right)
        {
            PrivilegeName = privName;
            Guid privId = left == null ? right.PrivilegeId : left.PrivilegeId;
            SystemPrivilege priv = allPrivilegesByGuid[privId];
            PrivilegeNameLong = priv.PrivilegeNameLong;

            LeftPrivilegeDepth = left == null ? (PrivilegeDepth?)null : left.Depth;
            LeftPrivilegeDepthTxt = FormatPrivilegeDepthTxt(LeftPrivilegeDepth);
            LeftPrivilegeDepthLong = FormatPrivilegeDepthCsv(LeftPrivilegeDepth);

            RightPrivilegeDepth = right == null ? (PrivilegeDepth?)null : right.Depth;
            RightPrivilegeDepthTxt = FormatPrivilegeDepthTxt(RightPrivilegeDepth);
            RightPrivilegeDepthLong = FormatPrivilegeDepthCsv(RightPrivilegeDepth);
        }

        /// <summary>
        /// Create an instance with only one set
        /// </summary>
        public RoleDiff(string privName, Dictionary<Guid, SystemPrivilege> allPrivilegesByGuid, RolePrivilege rolePriv)
        {
            PrivilegeName = privName;
            Guid privId = rolePriv.PrivilegeId;
            SystemPrivilege priv = allPrivilegesByGuid[privId];
            PrivilegeNameLong = priv.PrivilegeNameLong;

            LeftPrivilegeDepth = rolePriv == null ? (PrivilegeDepth?)null : rolePriv.Depth;
            LeftPrivilegeDepthTxt = FormatPrivilegeDepthTxt(LeftPrivilegeDepth);
            LeftPrivilegeDepthLong = FormatPrivilegeDepthCsv(LeftPrivilegeDepth);
        }

        /// <summary>
        /// Print for TXT output
        /// </summary>
        public string ToStringTxt()
        {
            return string.Format("{0,4} {1,5} {2}", LeftPrivilegeDepthTxt, RightPrivilegeDepthTxt, PrivilegeNameLong);
        }

        /// <summary>
        /// Print for TXT output (one set only)
        /// </summary>
        public string ToStringOneSetTxt()
        {
            return string.Format("{0,28} {1}", LeftPrivilegeDepthLong, PrivilegeNameLong);
        }

        /// <summary>
        /// Print for CSV output
        /// </summary>
        public string ToStringCsv()
        {
            return string.Format("{0},{1},{2},{3}", LeftPrivilegeDepthLong, RightPrivilegeDepthLong, PrivilegeName, PrivilegeNameLong);
        }

        /// <summary>
        /// Print for CSV output (one set only)
        /// </summary>
        public string ToStringOneSetCsv()
        {
            return string.Format("{0},{1},{2}", LeftPrivilegeDepthLong, PrivilegeName, PrivilegeNameLong);
        }

        /// <summary>
        /// Comparer for TXT format sort
        /// </summary>
        public static int CompareToStringTxt(string a, string b)
        {
            return a.Substring(11).CompareTo(b.Substring(11));
        }

        /// <summary>
        /// Comparer for TXT format sort (one set only)
        /// </summary>
        public static int CompareToStringOneSetTxt(string a, string b)
        {
            return a.Substring(29).CompareTo(b.Substring(29));
        }

        /// <summary>
        /// Comparer for CSV format sort
        /// </summary>
        public static int CompareToStringCsv(string a, string b)
        {
            string[] aa = a.Split(',');
            string[] bb = b.Split(',');

            return aa[3].CompareTo(bb[3]);
        }

        /// <summary>
        /// Comparer for CSV format sort (one set only)
        /// </summary>
        public static int CompareToStringOneSetCsv(string a, string b)
        {
            string[] aa = a.Split(',');
            string[] bb = b.Split(',');

            return aa[2].CompareTo(bb[2]);
        }

        #endregion

        #region Local Methods

        /// <summary>
        /// Format PrivilegeDepth for TXT output
        /// </summary>
        private string FormatPrivilegeDepthTxt(PrivilegeDepth? depth)
        {
            switch (depth)
            {
                case PrivilegeDepth.Basic:
                    return "1U";

                case PrivilegeDepth.Local:
                    return "2B";

                case PrivilegeDepth.Deep:
                    return "3P";

                case null:
                    return "  ";

                default:
                    return "4O";
            }
        }

        /// <summary>
        /// Format PrivilegeDepth for CSV output
        /// </summary>
        private string FormatPrivilegeDepthCsv(PrivilegeDepth? depth)
        {
            switch (depth)
            {
                case PrivilegeDepth.Basic:
                    return "User";

                case PrivilegeDepth.Local:
                    return "Business Unit";

                case PrivilegeDepth.Deep:
                    return "Parent: Child Business Units";

                case null:
                    return "None Selected";

                default:
                    return "Organization";
            }
        }

        #endregion

    }
}
